package com.zjs.utils;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.Data;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * 生成SQL语句工具类
 *
 * @author zhengJianSheng
 * @since 2023-06-16 14:05
 */
public class GenerateSqlUtil {
    /**
     * 工具类私有构造器
     */
    GenerateSqlUtil() {
        // 工具类不需要实例化
    }

    /**
     * 单个对象insert语句生成
     * @param bean      bean实体
     * @return  insert语句
     */
    @SuppressWarnings("unused")
    public static <T> String generateInsertSql(T bean) {
        return generateInsertSql(Collections.singletonList(bean));
    }

    /**
     * 根据Collection<T>去获取insert语句
     *
     * @param beanList     集合
     * @param <T>          泛型
     * @return insert语句
     */
    public static <T> String generateInsertSql(Collection<T> beanList) {
        if (CollectionUtils.isEmpty(beanList)) {
            return "";
        }
        GenerateSqlObj generateSqlObj = new GenerateSqlObj(beanList);
        return getInsertSqlByMap(generateSqlObj.getDataList(), generateSqlObj.getBeanClass());
    }

    /**
     * 获取传入的对象生成导出对应的sql，即delete语句 + insert语句
     * @param bean         bean对象
     * @return 生导出对应的sql，即delete语句 + insert语句
     */
    @SuppressWarnings("unused")
    public static <T> String generateExportSql(T bean) {
        return generateExportSql(Collections.singletonList(bean));
    }

    /**
     * 获取传入的对象集合生成导出对应的sql，即delete语句 + insert语句
     * @param beanList 数据集合
     * @param <T>          泛型
     * @return 生导出对应的sql，即delete语句 + insert语句
     */
    public static <T> String generateExportSql(Collection<T> beanList) {
        if (CollectionUtils.isEmpty(beanList)) {
            return "";
        }
        GenerateSqlObj generateSqlObj = new GenerateSqlObj(beanList);
        Class<?> beanClass = generateSqlObj.getBeanClass();
        List<Map<String, Object>> dataList = generateSqlObj.getDataList();

        String deleteSql = generateDeleteSqlByMap(dataList, beanClass);
        String insertSql = getInsertSqlByMap(dataList, beanClass);
        // 生成SQL语句
        return deleteSql + "\n\n" + insertSql;
    }

    /**
     * 根据Collection<Map<String, Object>>去获取insert语句
     *
     * @param dataList  集合
     * @param beanClass 类
     * @return insert语句
     */
    private static String getInsertSqlByMap(Collection<Map<String, Object>> dataList, Class<?> beanClass) {
        TableInfo tableInfo = TableInfoHelper.getTableInfo(beanClass);
        List<TableFieldInfo> tableFieldAll = tableInfo.getFieldList();
        int len = tableFieldAll.size() * 2;
        List<String> columnList = new ArrayList<>(len);
        List<String> fieldList = new ArrayList<>(len);
        String keyColumn = tableInfo.getKeyColumn();
        if (StringUtils.isNotBlank(keyColumn)) {
            columnList.add(keyColumn);
            fieldList.add(tableInfo.getKeyProperty());
        }
        tableFieldAll.forEach(tableFieldInfo -> {
            columnList.add(tableFieldInfo.getColumn());
            fieldList.add(tableFieldInfo.getProperty());
        });
        String columns = tableInfo.getAllSqlSelect();

        String valueSql = dataList.stream().map(data -> {
            StringJoiner values = new StringJoiner(",");
            fieldList.forEach(field -> {
                Object value = data.get(field);
                if (value instanceof String) {
                    value = "'" + value + "'";
                } else if (value instanceof Date) {
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    value = "'" + dateFormat.format((Date) value) + "'";
                }
                values.add(Objects.toString(value));
            });
            return String.format("(%s)", values);
        }).collect(Collectors.joining(", \n"));
        return String.format("INSERT INTO %s (%s) \nVALUES \n%s;", tableInfo.getTableName(), columns, valueSql);
    }

    /**
     * 获取delete 语句
     *
     * @param dataList  map集合
     * @param beanClass 类信息
     * @return deleteSQL
     */
    private static String generateDeleteSqlByMap(Collection<Map<String, Object>> dataList, Class<?> beanClass) {
        TableInfo tableInfo = TableInfoHelper.getTableInfo(beanClass);
        // 获取表名，ID的数据库和实体字段名
        String tableName = tableInfo.getTableName();
        String keyColumn = tableInfo.getKeyColumn();
        String keyProperty = tableInfo.getKeyProperty();
        // 获取ID集合
        String idJoin = dataList.stream().map(item -> Objects.toString(item.get(keyProperty))).collect(Collectors.joining(","));
        // 生成SQL语句
        return String.format("DELETE FROM %s WHERE %s IN (%s);", tableName, keyColumn, idJoin);
    }

    /**
     * 生成SQL对象
     */
    @Data
    private static class GenerateSqlObj {
        /**
         * bean对象class
         */
        private final Class<?> beanClass;

        /**
         * 数据集合
         */
        private final List<Map<String, Object>> dataList;

        public GenerateSqlObj(Collection<?> beanList) {
            this.beanClass = beanList.iterator().next().getClass();
            dataList = beanList.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());
        }

    }

}
